package net.lab1024.sa.admin.module.business.ball.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.admin.module.business.ball.bo.FuliBall;
import net.lab1024.sa.admin.module.business.ball.dao.FuliBallMapper;
import net.lab1024.sa.admin.module.business.ball.service.BallService;
import net.lab1024.sa.admin.module.business.ball.util.BallUtil;
import net.lab1024.sa.admin.module.business.ball.vo.DoubleColorBallVo;
import net.lab1024.sa.admin.module.business.ball.vo.ForecaseResult;
import org.apache.commons.lang3.time.DateUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 采集并存储最新的是双色球数据
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class BallServiceImpl extends ServiceImpl<FuliBallMapper, FuliBall> implements BallService {
    //获取历史数据中某些特征的数据：出现最多、最少、平均次数
    private int flag = 2;

    private final FuliBallMapper fuliBallDao;

    private final String dbColorDataurl = "http://datachart.500.com/ssq/history/newinc/history.php?limit=5000&sort=0";



    @Override
    public void updateDbColorBall() throws IOException {
        Document doc = Jsoup.connect(dbColorDataurl).get();
        List<FuliBall> ballList = parse(doc);
        saveOrUpdateBatch(ballList);
    }
    @Override
    public List<DoubleColorBallVo> dbColorForecast(Integer limit,String forecastFlag)   {
        LambdaQueryWrapper<FuliBall> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(FuliBall::getPhase).last("limit " + limit);
        List<FuliBall> balls = fuliBallDao.selectList(queryWrapper);

        if (balls.isEmpty()) {
            System.out.println("没有数据可供预测");
            return null;
        }
        //获取所有红球
        List<Integer> redList = Lists.newArrayList();
        List<Integer> blueList = Lists.newArrayList();
        balls.forEach(b -> {
            blueList.add(b.getBlue());
            redList.addAll(b.redNums());
        });
        List<Integer> redCountList = BallUtil.countAndSort(redList, 1,33);
        List<Integer> blueCountList = BallUtil.countAndSort(blueList, 1,16);
        FuliBall ball = new FuliBall();
        ball.redNums(redCountList.subList(0, 6));
        ball.setBlue(blueCountList.get(0));
        ball.setMsg("福彩双色球获取过去" + limit + "期内各个位置上出现次数" + ("1".equalsIgnoreCase(forecastFlag) ? "最多次数" : "最少次数") + "的数字");
        List<FuliBall> lists = Lists.newArrayList();
        lists.add(ball);
        return format(lists);
//        List<Integer> firstNumbers = extractNumbers(balls, 0);
//        List<Integer> secondNumbers = extractNumbers(balls, 1);
//        List<Integer> thirdNumbers = extractNumbers(balls, 2);
//        List<Integer> fourthNumbers = extractNumbers(balls, 3);
//        List<Integer> fifthNumbers = extractNumbers(balls, 4);
//        List<Integer> sixthNumbers = extractNumbers(balls, 5);
//        List<Integer> seventhNumbers = extractNumbers(balls, 6);
//
//        int average = (int) Math.round((double) firstNumbers.size() * 7 / balls.size());
//
//        int firstCount = getMostFrequentNumber(firstNumbers,forecastFlag);
//        int secondCount = getMostFrequentNumber(secondNumbers,forecastFlag);
//        int thirdCount = getMostFrequentNumber(thirdNumbers,forecastFlag);
//        int fourthCount = getMostFrequentNumber(fourthNumbers,forecastFlag);
//        int fifthCount = getMostFrequentNumber(fifthNumbers,forecastFlag);
//        int sixthCount = getMostFrequentNumber(sixthNumbers,forecastFlag);
//        int seventhCount = getMostFrequentNumber(seventhNumbers,forecastFlag);
//
//        int[] mostNumbers = {firstCount, secondCount, thirdCount, fourthCount, fifthCount, sixthCount, seventhCount};
//
//        ForecaseResult forecaseResult = printForecastResults(mostNumbers, average);
//        return forecaseResult.getBalls();

    }

    /**
     * 格式化成vo
     * @param list
     * @return
     */
    @Override
    public List<DoubleColorBallVo> format(List<FuliBall> list) {
        return list.stream().map(b -> {
            DoubleColorBallVo vo = new DoubleColorBallVo();
            if (b.getPhase() != null) {
                vo.setPhase(b.getPhase() + "期");
            }
            vo.setRed1(String.format("%02d", b.getRed1()));
            vo.setRed2(String.format("%02d", b.getRed2()));
            vo.setRed3(String.format("%02d", b.getRed3()));
            vo.setRed4(String.format("%02d", b.getRed4()));
            vo.setRed5(String.format("%02d", b.getRed5()));
            vo.setRed6(String.format("%02d", b.getRed6()));
            vo.setBlue(String.format("%02d", b.getBlue()));
            vo.setDrawDate(b.getDrawDate());
            vo.setMsg(b.getMsg());
            return vo;
        }).collect(Collectors.toList());
    }


    private int getMostFrequentNumber(List<Integer> numbers,String getFlag) {
        Map<Integer, Integer> countMap = new HashMap<>();
        for (int number : numbers) {
            countMap.put(number, countMap.getOrDefault(number, 0) + 1);
        }
        if (getFlag.equals("1")) {
            return Collections.max(countMap.entrySet(), Map.Entry.comparingByValue()).getKey();
        } else {
            return Collections.min(countMap.entrySet(), Map.Entry.comparingByValue()).getKey();
        }
    }

    private ForecaseResult printForecastResults(int[] mostNumbers, int average) {
        StringBuilder forecastNumbers = new StringBuilder();
        double totalChance = 0.0;

        for (int i = 0; i < mostNumbers.length; i++) {
            int number = mostNumbers[i];
            double probability = (double) countOccurrences(mostNumbers, number) / average * 100;
            forecastNumbers.append(number).append(" ");
            totalChance += probability;
        }

        double averageChance = totalChance / mostNumbers.length;
        DecimalFormat decimalFormat = new DecimalFormat("#.##");
        log.info("预测号码：" + forecastNumbers.toString().trim());
        log.info("中奖概率：" + decimalFormat.format(averageChance) + "%");
        return new ForecaseResult(forecastNumbers.toString().trim(), decimalFormat.format(averageChance) + "%");
    }

    private int countOccurrences(int[] numbers, int target) {
        int count = 0;
        for (int number : numbers) {
            if (number == target) {
                count++;
            }
        }
        return count;
    }
    private List<FuliBall> parse(Document doc)   {
        Elements phaseElements = doc.select("tr.t_tr1 > td:nth-child(1)");
        Elements redBall1Elements = doc.select("tr.t_tr1 > td:nth-child(2)");
        Elements redBall2Elements = doc.select("tr.t_tr1 > td:nth-child(3)");
        Elements redBall3Elements = doc.select("tr.t_tr1 > td:nth-child(4)");
        Elements redBall4Elements = doc.select("tr.t_tr1 > td:nth-child(5)");
        Elements redBall5Elements = doc.select("tr.t_tr1 > td:nth-child(6)");
        Elements redBall6Elements = doc.select("tr.t_tr1 > td:nth-child(7)");
        Elements blueBallElements = doc.select("tr.t_tr1 > td:nth-child(8)");
        Elements dateElements = doc.select("tr.t_tr1 > td:last-child");

        //过滤掉已有的
        List<Integer> phaseList = phaseElements.stream().map(e -> Integer.valueOf(e.text())).collect(Collectors.toList());


        LambdaQueryWrapper<FuliBall> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(FuliBall::getPhase, phaseList);
        List<FuliBall> existBallList = fuliBallDao.selectList(queryWrapper);

        Set<Integer> existPhaseSet = existBallList.stream().map(b -> b.getPhase()).collect(Collectors.toSet());
        return phaseElements.stream()
                .filter(p -> !existPhaseSet.contains(Integer.valueOf(p.text())))
                .map(phaseElement -> {
                    int index = phaseElements.indexOf(phaseElement);
                    Element dateElement = dateElements.get(index);
                    Integer phase = Integer.parseInt(phaseElement.text());
                    Integer red1 = Integer.valueOf(redBall1Elements.get(index).text());
                    Integer red2 = Integer.valueOf(redBall2Elements.get(index).text());
                    Integer red3 = Integer.valueOf(redBall3Elements.get(index).text());
                    Integer red4 = Integer.valueOf(redBall4Elements.get(index).text());
                    Integer red5 = Integer.valueOf(redBall5Elements.get(index).text());
                    Integer red6 = Integer.valueOf(redBall6Elements.get(index).text());
                    Integer blueBall = Integer.valueOf(blueBallElements.get(index).text());
                    Date drawDate = null;
                    try {
                        log.info(dateElement.text());
                        drawDate = DateUtils.parseDate(dateElement.text());
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    return new FuliBall(phase, red1, red2, red3, red4, red5,red6, blueBall, drawDate);
                })
                .collect(Collectors.toList());
    }


}
